using System.Reflection;
using System.Runtime.Loader;

namespace sgf.server
{
    public static class HotfixMgr
    {
        private static Assembly _hotfixDll = null!;

        private static AssemblyLoadContext _context = null!;

        private static readonly Dictionary<Type, IMessageHandler> MessageHandlers = new();

        private static readonly Dictionary<string, IHttpMsgHandler> HttpMsgHandlers = new();

        private static readonly Dictionary<string, List<ISystemType>> TypeSystemsMap = new();

        public static void Load()
        {
            InitCore();
            _context?.Unload();
            GC.Collect();
            _context = new AssemblyLoadContext("Hotfix", true);
            byte[] dllBytes = File.ReadAllBytes("./server.hotfix.dll");
            byte[] pdbBytes = File.ReadAllBytes("./server.hotfix.pdb");
            Assembly hotfixAssembly = _context.LoadFromStream(new MemoryStream(dllBytes), new MemoryStream(pdbBytes));
        }

        private static void InitCore()
        {
            MessageHandlers[typeof(CheckStartReq)] = new CheckStartHandler();
        }

        public static void LoadAssembly(Assembly hotfixDll)
        {
            foreach (var type in hotfixDll.GetTypes())
            {
                if (type.GetInterfaces().Contains(typeof(IMessageHandler)) && !type.IsAbstract)
                {
                    var msgHandler = (IMessageHandler)Activator.CreateInstance(type)!;
                    MessageHandlers[msgHandler.GetMessageType()] = msgHandler;
                }

                if (type.GetInterfaces().Contains(typeof(IHttpMsgHandler)) && !type.IsAbstract)
                {
                    var msgHandler = (IHttpMsgHandler)Activator.CreateInstance(type)!;
                    HttpMsgHandlers[msgHandler.GetPrefix()] = msgHandler;
                }

                if (type.GetInterfaces().Contains(typeof(ISystemType)) && !type.IsAbstract)
                {
                    var eventSystem = (ISystemType)Activator.CreateInstance(type)!;
                    var eventType = eventSystem.Type();
                    var eventTypeFullName = eventType.FullName;
                    if (eventTypeFullName == null) continue;
                    if (!TypeSystemsMap.ContainsKey(eventTypeFullName))
                    {
                        TypeSystemsMap[eventTypeFullName] = [];
                    }

                    TypeSystemsMap[eventTypeFullName].Add(eventSystem);
                }
            }
        }

        public static IMessageHandler? GetMessageHandler(Type type)
        {
            MessageHandlers.TryGetValue(type, out var outHandler);
            return outHandler;
        }

        public static IHttpMsgHandler? GetHttpMsgHandler(string prefix)
        {
            HttpMsgHandlers.TryGetValue(prefix, out var outHandler);
            return outHandler;
        }

        public static List<T> GetSystemTypes<T>(Type type) where T : ISystemType
        {
            var typeFullName = type.FullName;
            if (typeFullName == null) return [];
            TypeSystemsMap.TryGetValue(typeFullName, out var types);
            return types?.OfType<T>().ToList() ?? [];
        }

        // class HostAssemblyLoadContext : AssemblyLoadContext
        // {
        //     private readonly Dictionary<string, Assembly> _loadedAssemblies = new();
        //
        //     public HostAssemblyLoadContext() : base(true)
        //     {
        //     }
        //
        //     protected override Assembly Load(AssemblyName assemblyName)
        //     {
        //         if (_loadedAssemblies.TryGetValue(assemblyName.FullName, out var assembly))
        //         {
        //             return assembly;
        //         }
        //
        //         var assemblyPath = Path.Combine(Environment.CurrentDirectory, $"{assemblyName.Name}.dll");
        //         if (File.Exists(assemblyPath))
        //         {
        //             assembly = LoadFromAssemblyPath(assemblyPath);
        //             _loadedAssemblies[assemblyName.FullName] = assembly;
        //             return assembly;
        //         }
        //
        //         return null;
        //     }
        // }
    }
}